<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>46.4. Writing Validators</title>
<link rel="stylesheet" href="dbstyle.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.72.0">
<link rel="start" href="index.html" title="Programmer's Reference Guide">
<link rel="up" href="zend.validate.html" title="Chapter 46. Zend_Validate">
<link rel="prev" href="zend.validate.validator_chains.html" title="46.3. Validator Chains">
<link rel="next" href="zend.version.html" title="Chapter 47. Zend_Version">
<link rel="chapter" href="introduction.html" title="Chapter 1. Introduction to Zend Framework">
<link rel="chapter" href="zend.acl.html" title="Chapter 2. Zend_Acl">
<link rel="chapter" href="zend.auth.html" title="Chapter 3. Zend_Auth">
<link rel="chapter" href="zend.cache.html" title="Chapter 4. Zend_Cache">
<link rel="chapter" href="zend.config.html" title="Chapter 5. Zend_Config">
<link rel="chapter" href="zend.console.getopt.html" title="Chapter 6. Zend_Console_Getopt">
<link rel="chapter" href="zend.controller.html" title="Chapter 7. Zend_Controller">
<link rel="chapter" href="zend.currency.html" title="Chapter 8. Zend_Currency">
<link rel="chapter" href="zend.date.html" title="Chapter 9. Zend_Date">
<link rel="chapter" href="zend.db.html" title="Chapter 10. Zend_Db">
<link rel="chapter" href="zend.debug.html" title="Chapter 11. Zend_Debug">
<link rel="chapter" href="zend.dojo.html" title="Chapter 12. Zend_Dojo">
<link rel="chapter" href="zend.dom.html" title="Chapter 13. Zend_Dom">
<link rel="chapter" href="zend.exception.html" title="Chapter 14. Zend_Exception">
<link rel="chapter" href="zend.feed.html" title="Chapter 15. Zend_Feed">
<link rel="chapter" href="zend.filter.html" title="Chapter 16. Zend_Filter">
<link rel="chapter" href="zend.form.html" title="Chapter 17. Zend_Form">
<link rel="chapter" href="zend.gdata.html" title="Chapter 18. Zend_Gdata">
<link rel="chapter" href="zend.http.html" title="Chapter 19. Zend_Http">
<link rel="chapter" href="zend.infocard.html" title="Chapter 20. Zend_InfoCard">
<link rel="chapter" href="zend.json.html" title="Chapter 21. Zend_Json">
<link rel="chapter" href="zend.layout.html" title="Chapter 22. Zend_Layout">
<link rel="chapter" href="zend.ldap.html" title="Chapter 23. Zend_Ldap">
<link rel="chapter" href="zend.loader.html" title="Chapter 24. Zend_Loader">
<link rel="chapter" href="zend.locale.html" title="Chapter 25. Zend_Locale">
<link rel="chapter" href="zend.log.html" title="Chapter 26. Zend_Log">
<link rel="chapter" href="zend.mail.html" title="Chapter 27. Zend_Mail">
<link rel="chapter" href="zend.measure.html" title="Chapter 28. Zend_Measure">
<link rel="chapter" href="zend.memory.html" title="Chapter 29. Zend_Memory">
<link rel="chapter" href="zend.mime.html" title="Chapter 30. Zend_Mime">
<link rel="chapter" href="zend.openid.html" title="Chapter 31. Zend_OpenId">
<link rel="chapter" href="zend.paginator.html" title="Chapter 32. Zend_Paginator">
<link rel="chapter" href="zend.pdf.html" title="Chapter 33. Zend_Pdf">
<link rel="chapter" href="zend.registry.html" title="Chapter 34. Zend_Registry">
<link rel="chapter" href="zend.rest.html" title="Chapter 35. Zend_Rest">
<link rel="chapter" href="zend.search.lucene.html" title="Chapter 36. Zend_Search_Lucene">
<link rel="chapter" href="zend.server.html" title="Chapter 37. Zend_Server">
<link rel="chapter" href="zend.service.html" title="Chapter 38. Zend_Service">
<link rel="chapter" href="zend.session.html" title="Chapter 39. Zend_Session">
<link rel="chapter" href="zend.soap.html" title="Chapter 40. Zend_Soap">
<link rel="chapter" href="zend.test.html" title="Chapter 41. Zend_Test">
<link rel="chapter" href="zend.text.html" title="Chapter 42. Zend_Text">
<link rel="chapter" href="zend.timesync.html" title="Chapter 43. Zend_TimeSync">
<link rel="chapter" href="zend.translate.html" title="Chapter 44. Zend_Translate">
<link rel="chapter" href="zend.uri.html" title="Chapter 45. Zend_Uri">
<link rel="chapter" href="zend.validate.html" title="Chapter 46. Zend_Validate">
<link rel="chapter" href="zend.version.html" title="Chapter 47. Zend_Version">
<link rel="chapter" href="zend.view.html" title="Chapter 48. Zend_View">
<link rel="chapter" href="zend.xmlrpc.html" title="Chapter 49. Zend_XmlRpc">
<link rel="appendix" href="requirements.html" title="Appendix A. Zend Framework Requirements">
<link rel="appendix" href="coding-standard.html" title="Appendix B. Zend Framework Coding Standard for PHP">
<link rel="appendix" href="copyrights.html" title="Appendix C. Copyright Information">
<link rel="index" href="the.index.html" title="Index">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader"><table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">46.4. Writing Validators</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="zend.validate.validator_chains.html">Prev</a> </td>
<th width="60%" align="center">Chapter 46. Zend_Validate</th>
<td width="20%" align="right"> <a accesskey="n" href="zend.version.html">Next</a>
</td>
</tr>
</table></div>
<div class="sect1" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="zend.validate.writing_validators"></a>46.4. Writing Validators</h2></div></div></div>
<p>
        Zend_Validate supplies a set of commonly needed validators, but inevitably, developers will wish to
        write custom validators for their particular needs. The task of writing a custom validator is
        described in this section.
    </p>
<p>
        <code class="code">Zend_Validate_Interface</code> defines three methods, <code class="code">isValid()</code>,
        <code class="code">getMessages()</code>, and <code class="code">getErrors()</code>, that may be implemented by user classes in order to
        create custom validation objects. An object that implements <code class="code">Zend_Validate_Interface</code> interface
        may be added to a validator chain with <code class="code">Zend_Validate::addValidator()</code>. Such objects may also be
        used with <a href="zend.filter.input.html" title="16.5. Zend_Filter_Input"><code class="code">Zend_Filter_Input</code></a>.
    </p>
<p>
        As you may already have inferred from the above description of <code class="code">Zend_Validate_Interface</code>,
        validation classes provided with Zend Framework return a boolean value for whether or not a value validates
        successfully. They also provide information about <span class="bold"><strong>why</strong></span> a value failed
        validation. The availability of the reasons for validation failures may be valuable to an application for
        various purposes, such as providing statistics for usability analysis.
    </p>
<p>
        Basic validation failure message functionality is implemented in <code class="code">Zend_Validate_Abstract</code>. To
        include this functionality when creating a validation class, simply extend
        <code class="code">Zend_Validate_Abstract</code>. In the extending class you would implement the
        <code class="code">isValid()</code> method logic and define the message variables and message templates that correspond to
        the types of validation failures that can occur. If a value fails your validation tests, then
        <code class="code">isValid()</code> should return <code class="code">false</code>. If the value passes your validation tests, then
        <code class="code">isValid()</code> should return <code class="code">true</code>.
    </p>
<p>
        In general, the <code class="code">isValid()</code> method should not throw any exceptions, except where it is impossible
        to determine whether or not the input value is valid. A few examples of reasonable cases for throwing an
        exception might be if a file cannot be opened, an LDAP server could not be contacted, or a database
        connection is unavailable, where such a thing may be required for validation success or failure to be
        determined.
    </p>
<div class="example">
<a name="zend.validate.writing_validators.example.simple"></a><p class="title"><b>Example 46.1. Creating a Simple Validation Class</b></p>
<div class="example-contents">
<p>
            The following example demonstrates how a very simple custom validator might be written. In this case the
            validation rules are simply that the input value must be a floating point value.

            </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/Validate/Abstract.php';

class MyValid_Float extends Zend_Validate_Abstract
{
    const FLOAT = 'float';

    protected $_messageTemplates = array(
        self::FLOAT =&gt; "'%value%' is not a floating point value"
    );

    public function isValid($value)
    {
        $this-&gt;_setValue($value);

        if (!is_float($value)) {
            $this-&gt;_error();
            return false;
        }

        return true;
    }
}
            </pre>
<p>

            The class defines a template for its single validation failure message, which includes the built-in magic
            parameter, <code class="code">%value%</code>. The call to <code class="code">_setValue()</code> prepares the object to insert the
            tested value into the failure message automatically, should the value fail validation. The call to
            <code class="code">_error()</code> tracks a reason for validation failure. Since this class only defines one failure
            message, it is not necessary to provide <code class="code">_error()</code> with the name of the failure message
            template.
        </p>
</div>
</div>
<br class="example-break"><div class="example">
<a name="zend.validate.writing_validators.example.conditions.dependent"></a><p class="title"><b>Example 46.2. Writing a Validation Class having Dependent Conditions</b></p>
<div class="example-contents">
<p>
            The following example demonstrates a more complex set of validation rules, where it is required that the
            input value be numeric and within the range of minimum and maximum boundary values. An input value would
            fail validation for exactly one of the following reasons:

            </p>
<div class="itemizedlist"><ul type="disc">
<li><p>The input value is not numeric.</p></li>
<li><p>The input value is less than the minimum allowed value.</p></li>
<li><p>The input value is more than the maximum allowed value.</p></li>
</ul></div>
<p>
        </p>
<p>
            These validation failure reasons are then translated to definitions in the class:

            </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/Validate/Abstract.php';

class MyValid_NumericBetween extends Zend_Validate_Abstract
{
    const MSG_NUMERIC = 'msgNumeric';
    const MSG_MINIMUM = 'msgMinimum';
    const MSG_MAXIMUM = 'msgMaximum';

    public $minimum = 0;
    public $maximum = 100;

    protected $_messageVariables = array(
        'min' =&gt; 'minimum',
        'max' =&gt; 'maximum'
    );

    protected $_messageTemplates = array(
        self::MSG_NUMERIC =&gt; "'%value%' is not numeric",
        self::MSG_MINIMUM =&gt; "'%value%' must be at least '%min%'",
        self::MSG_MAXIMUM =&gt; "'%value%' must be no more than '%max%'"
    );

    public function isValid($value)
    {
        $this-&gt;_setValue($value);

        if (!is_numeric($value)) {
            $this-&gt;_error(self::MSG_NUMERIC);
            return false;
        }

        if ($value &lt; $this-&gt;minimum) {
            $this-&gt;_error(self::MSG_MINIMUM);
            return false;
        }

        if ($value &gt; $this-&gt;maximum) {
            $this-&gt;_error(self::MSG_MAXIMUM);
            return false;
        }

        return true;
    }
}
            </pre>
<p>

            The public properties <code class="code">$minimum</code> and <code class="code">$maximum</code> have been established to provide
            the minimum and maximum boundaries, respectively, for a value to successfully validate. The class also
            defines two message variables that correspond to the public properties and allow <code class="code">min</code> and
            <code class="code">max</code> to be used in message templates as magic parameters, just as with <code class="code">value</code>.
        </p>
<p>
            Note that if any one of the validation checks in <code class="code">isValid()</code> fails, an appropriate failure
            message is prepared, and the method immediately returns <code class="code">false</code>. These validation rules are
            therefore sequentially dependent. That is, if one test should fail, there is no need to test any
            subsequent validation rules. This need not be the case, however. The following example illustrates how to
            write a class having independent validation rules, where the validation object may return multiple
            reasons why a particular validation attempt failed.
        </p>
</div>
</div>
<br class="example-break"><div class="example">
<a name="zend.validate.writing_validators.example.conditions.independent"></a><p class="title"><b>Example 46.3. Validation with Independent Conditions, Multiple Reasons for Failure</b></p>
<div class="example-contents">
<p>
            Consider writing a validation class for password strength enforcement - when a user is required to choose
            a password that meets certain criteria for helping secure user accounts. Let us assume that the password
            security criteria enforce that the password:

            </p>
<div class="itemizedlist"><ul type="disc">
<li><p>is at least 8 characters in length,</p></li>
<li><p>contains at least one uppercase letter,</p></li>
<li><p>contains at least one lowercase letter,</p></li>
<li><p>and contains at least one digit character.</p></li>
</ul></div>
<p>
        </p>
<p>
            The following class implements these validation criteria:

            </p>
<pre class="programlisting">&lt;?php
require_once 'Zend/Validate/Abstract.php';

class MyValid_PasswordStrength extends Zend_Validate_Abstract
{
    const LENGTH = 'length';
    const UPPER  = 'upper';
    const LOWER  = 'lower';
    const DIGIT  = 'digit';

    protected $_messageTemplates = array(
        self::LENGTH =&gt; "'%value%' must be at least 8 characters in length",
        self::UPPER  =&gt; "'%value%' must contain at least one uppercase letter",
        self::LOWER  =&gt; "'%value%' must contain at least one lowercase letter",
        self::DIGIT  =&gt; "'%value%' must contain at least one digit character"
    );

    public function isValid($value)
    {
        $this-&gt;_setValue($value);

        $isValid = true;

        if (strlen($value) &lt; 8) {
            $this-&gt;_error(self::LENGTH);
            $isValid = false;
        }

        if (!preg_match('/[A-Z]/', $value)) {
            $this-&gt;_error(self::UPPER);
            $isValid = false;
        }

        if (!preg_match('/[a-z]/', $value)) {
            $this-&gt;_error(self::LOWER);
            $isValid = false;
        }

        if (!preg_match('/\d/', $value)) {
            $this-&gt;_error(self::DIGIT);
            $isValid = false;
        }

        return $isValid;
    }
}
            </pre>
<p>

            Note that the four criteria tests in <code class="code">isValid()</code> do not immediately return <code class="code">false</code>.
            This allows the validation class to provide <span class="bold"><strong>all</strong></span> of the reasons that the
            input password failed to meet the validation requirements. If, for example, a user were to input the
            string "<code class="code">#$%</code>" as a password, <code class="code">isValid()</code> would cause all four validation failure
            messages to be returned by a subsequent call to <code class="code">getMessages()</code>.
        </p>
</div>
</div>
<br class="example-break">
</div>
<div class="navfooter"><table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="zend.validate.validator_chains.html">Prev</a> </td>
<td width="20%" align="center"><a accesskey="u" href="zend.validate.html">Up</a></td>
<td width="40%" align="right"> <a accesskey="n" href="zend.version.html">Next</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">46.3. Validator Chains </td>
<td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
<td width="40%" align="right" valign="top"> Chapter 47. Zend_Version</td>
</tr>
</table></div>
<div class="revinfo"></div>
</body>
</html>
